package com.pzh.assignment.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pzh.assignment.common.bean.Result;
import com.pzh.assignment.common.bean.param.ProgramCopyParam;
import com.pzh.assignment.common.bean.param.ProgramParam;
import com.pzh.assignment.common.bean.vo.ProgramDataVO;
import com.pzh.assignment.common.bean.vo.ProgramVO;
import com.pzh.assignment.common.shiro.ShiroUtils;
import com.pzh.assignment.entity.Class;
import com.pzh.assignment.entity.Grade;
import com.pzh.assignment.entity.Groups;
import com.pzh.assignment.entity.Major;
import com.pzh.assignment.entity.Plan;
import com.pzh.assignment.entity.Program;
import com.pzh.assignment.entity.Role;
import com.pzh.assignment.entity.Semester;
import com.pzh.assignment.service.IClassService;
import com.pzh.assignment.service.IGradeService;
import com.pzh.assignment.service.IGroupsService;
import com.pzh.assignment.service.IMajorService;
import com.pzh.assignment.service.IPlanService;
import com.pzh.assignment.service.IProgramService;
import com.pzh.assignment.service.ISemesterService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author pengzhihao
 * @since 2022-04-16
 */
@RestController
@RequestMapping("/program")
public class ProgramController {

    @Autowired
    IProgramService programService;
    @Autowired
    IGradeService gradeService;
    @Autowired
    ISemesterService semesterService;
    @Autowired
    IPlanService planService;
    @Autowired
    IClassService classService;
    @Autowired
    IGroupsService groupsService;
    @Autowired
    IMajorService majorService;

    @RequiresRoles(value = {"sys_admin", "admin"}, logical = Logical.OR)
    @GetMapping
    public Result listProgramByPage(@RequestParam(defaultValue = "1") Integer currentPage,
                                  @RequestParam(defaultValue = "5") Integer size) {
        Page<Program> page = new Page<>(currentPage, size);
        QueryWrapper<Program> programQueryWrapper = initProgramWrapper();
        programQueryWrapper.groupBy("grade_id", "major_id");
        IPage pageData = programService.page(page, programQueryWrapper);
        List<ProgramVO> voList = ((IPage<Program>) pageData).getRecords().stream().map(ProgramVO::valueOf).collect(Collectors.toList());
        pageData.setRecords(voList);
        return Result.success(pageData);
    }

    @RequiresRoles(value = {"sys_admin", "admin"}, logical = Logical.OR)
    @GetMapping("/details")
    public Result details(@RequestParam Integer gradeId, @RequestParam Integer majorId) {
        HashMap<String, Integer> eqMap = new HashMap<>();
        eqMap.put("major_id", majorId);
        eqMap.put("grade_id", gradeId);
        QueryWrapper<Program> programQueryWrapper = initProgramWrapper();
        programQueryWrapper.allEq(eqMap);
        List<Program> programList = programService.list(programQueryWrapper);
        List<ProgramDataVO> voList = programList.stream().map(ProgramDataVO::valueOf).collect(Collectors.toList());
        return Result.success(voList);
    }

    @RequiresRoles(value = {"sys_admin", "admin"}, logical = Logical.OR)
    @PostMapping("/copy")
    public Result copy(@RequestBody ProgramCopyParam param) {
        HashMap<String, Integer> eqMap = new HashMap<>();
        eqMap.put("major_id", param.getOldMajor());
        eqMap.put("grade_id", param.getOldGrade());
        QueryWrapper<Program> programQueryWrapper = initProgramWrapper();
        programQueryWrapper.allEq(eqMap);
        List<Program> programList = programService.list(programQueryWrapper);
        for (Program program : programList) {
            program.setId(null);
            program.setMajorId(param.getMajorId());
            program.setGradeId(param.getGradeId());
            programService.save(program);
            Grade grade = gradeService.getById(program.getGradeId());
            Semester semester = judgeSemester(program.getTerm(), grade.getGrade());
            //获取课程教学总人数
            int totalNum = totalNumber(param.getMajorId(), grade.getGrade());
            //添加教学计划
            Plan plan = new Plan();
            plan.setProgramId(program.getId());
            plan.setSemesterId(semester.getId());
            plan.setTotalNum(totalNum);
            plan.setRemainNum(totalNum);
            planService.save(plan);
        }
        return Result.success(null);
    }

    @GetMapping("/total")
    public Result totalProgram() {
        QueryWrapper<Program> programQueryWrapper = initProgramWrapper();
        List<Program> programs = programService.list(programQueryWrapper);
        List<ProgramVO> voList = programs.stream().map(ProgramVO::valueOf).collect(Collectors.toList());
        return Result.success(voList);
    }



    @RequiresRoles(value = {"sys_admin", "admin"}, logical = Logical.OR)
    @PostMapping
    public Result saveOrUpdate(@RequestBody ProgramParam param) {
        Grade grade = gradeService.getById(param.getGradeId());
        Integer gradeNum = grade.getGrade();
        //判断是否需要添加学期
        Semester semester = judgeSemester(param.getTerm(), gradeNum);
        Program program = Program.valueOf(param);
        if (param.getId() != null) {
            //id 不为空，更新操作
            programService.saveOrUpdate(program);
        } else {
            //添加操作
            programService.save(program);
            //获取课程教学总人数
            int totalNum = totalNumber(param.getMajorId(), gradeNum);
            //添加教学计划
            Plan plan = new Plan();
            plan.setProgramId(program.getId());
            plan.setSemesterId(semester.getId());
            plan.setTotalNum(totalNum);
            plan.setRemainNum(totalNum);
            planService.save(plan);
        }
        return Result.success(null);
    }

    @RequiresRoles(value = {"sys_admin", "admin"}, logical = Logical.OR)
    @DeleteMapping
    public Result delete(@RequestParam Integer id) {
        programService.removeById(id);
        planService.remove(new QueryWrapper<Plan>().eq("program_id", id));
        return Result.success(null);
    }
    
    /** 
     * @description:  判断是否需要添加学期
     * @param: param
     * @return: com.pzh.assignment.entity.Semester 
     * @author pengzhihao
     * @date: 2022/5/18
     */ 
    private Semester judgeSemester(Integer term, Integer gradeNum) {
        //计算学期
        Integer year = gradeNum + ((term - 1) / 2);
        Integer number = (term % 2 == 0) ? 2 : 1;
        HashMap<String, Integer> eqMap = new HashMap<>();
        eqMap.put("year", year);
        eqMap.put("number", number);
        Semester semester = semesterService.getOne(new QueryWrapper<Semester>().allEq(eqMap));
        if (semester == null) {
            //需要添加
            semester = new Semester();
            semester.setNumber(number);
            semester.setYear(year);
            semesterService.save(semester);
        }
        return semester;
    }

    /**
     * @description:  获取课程教学总人数
     * @param: majorId
     * @param: gradeNum
     * @return: int
     * @author pengzhihao
     * @date: 2022/5/18
     */
    private int totalNumber(int majorId, int gradeNum) {
        HashMap<String, Integer> eqMap = new HashMap<>();
        eqMap.put("major_id", majorId);
        eqMap.put("grade", gradeNum);
        List<Class> classList = classService.list(new QueryWrapper<Class>().allEq(eqMap));
        return classList.stream().mapToInt(Class::getPeopleNum).sum();
    }

    private QueryWrapper<Program> initProgramWrapper(){
        Role role = ShiroUtils.getProfile().getRole();
        Integer groupId = ShiroUtils.getProfile().getGroupId();
        QueryWrapper<Program> wrapper = new QueryWrapper<>();
        switch (role.getName()) {
            case Role.SYSTEM_ADMIN:{
                wrapper.orderByDesc("create_time");
                break;
            }
            default:{
                Groups group = groupsService.getById(groupId);
                List<Major> majorList = majorService.list(new QueryWrapper<Major>().eq("college_id", group.getCollegeId()));
                List<Integer> majorIds = majorList.stream().map(major -> major.getId()).collect(Collectors.toList());
                wrapper.in("major_id", majorIds).orderByDesc("create_time");
                break;
            }
        }
        return wrapper;
    }
}
